Crate by_address

source ·
Expand description

Wrapper type for by-address hashing and comparison.

ByAddress can be used to wrap any pointer type (i.e. any type that implements the Deref trait). This includes references, raw pointers, smart pointers like Rc<T> and Box<T>, and specialized pointer-like types such as Vec<T> and String.

Comparison, ordering, and hashing of the wrapped pointer will be based on the address of its contents, rather than their value.

use by_address::ByAddress;
use std::rc::Rc;

let rc = Rc::new(5);
let x = ByAddress(rc.clone());
let y = ByAddress(rc.clone());

// x and y are two pointers to the same address:
assert_eq!(x, y);

let z = ByAddress(Rc::new(5));

// *x and *z have the same value, but not the same address:
assert_ne!(x, z);

If T is a pointer to an unsized type, then comparison of ByAddress<T> uses the entire fat pointer, not just the “thin” data address. This means that two slice pointers are consider equal only if they have the same starting address and length.

let v = [1, 2, 3, 4];

assert_eq!(ByAddress(&v[0..4]), ByAddress(&v[0..4])); // Same address and length.
assert_ne!(ByAddress(&v[0..4]), ByAddress(&v[0..2])); // Same address, different length.

You can use ByThinAddress instead if you want to compare slices by starting address only, or trait objects by data pointer only.

You can use wrapped pointers as keys in hashed or ordered collections, like BTreeMap/BTreeSet or HashMap/HashSet, even if the target of the pointer doesn’t implement hashing or ordering. This even includes pointers to trait objects, which usually don’t implement the Eq trait because it is not object-safe.

/// Call each item in `callbacks`, skipping any duplicate references.
fn call_each_once(callbacks: &[&dyn Fn()]) {
    let mut seen: HashSet<ByAddress<&dyn Fn()>> = HashSet::new();
    for &f in callbacks {
        if seen.insert(ByAddress(f)) {
            f();
        }
    }
}

However, note that comparing fat pointers to trait objects can be unreliable because of Rust issue #46139. In some cases, ByThinAddress may be more useful.

This crate does not depend on libstd, so it can be used in no_std projects.

Structs§